package language;

import lombok.Data;
import org.junit.Test;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;

public class distinct {

    //重写equals和hashcode方法，将实体类某几个字段相同就判定为相同
    @Test
    public void streamDistinct(){
        List<Student> stringList = this.getData();
        List<Student> collect = stringList.stream().distinct().collect(Collectors.toList());
        System.out.println(collect);
    }

    //根据List<Object>中 Object 某个属性去重 1
    @Test public void treeSet(){
        List<Student> data = this.getData();

        List<Student> collect = data.stream().collect(
                collectingAndThen(
                        toCollection(() -> new TreeSet<>(Comparator.comparing(Student::getStuNo))), ArrayList::new)
        );
        System.out.println("finish");
    }

    //根据List<Object>中 Object 某个属性去重 2
    @Test public void streamFilter(){
        List<Student> data = this.getData();
        List<Student> collect = data.stream().filter(distinctByKey(Student::getStuNo)).collect(Collectors.toList());
        System.out.println("finish");
    }

    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(keyExtractor.apply(t));
    }

    private List<Student> getData(){
        List<Student> sts = new ArrayList<>();
        Student s1 = new Student();
        s1.setStuNo("aa");
        s1.setName("name");
        s1.setSchool("school1");

        Student s2 = new Student();
        s2.setStuNo("aa");
        s2.setName("name");
        s2.setSchool("school2");

        Student s3 = new Student();
        s3.setStuNo("aa");
        s3.setName("name2");


        sts.add(s1);
        sts.add(s2);
        sts.add(s3);
        return sts;
    }

}

@Data
class Student {
    private String stuNo;
    private String name;

    private String school;

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (stuNo == null) {
            if (other.stuNo != null)
                return false;
        } else if (!stuNo.equals(other.stuNo))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((stuNo == null) ? 0 : stuNo.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

}